﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Text.RegularExpressions;
using System.Runtime.Serialization.Formatters.Binary;
using System.IO;
using PServiceBus.Core.Runtime;
using PServiceBus.Core.Logger;
using PServiceBus.Core.Interface;
using PServiceBus.Core.Runtime.Extensions;
using System.Collections;
using System.Threading.Tasks;
using System.Collections.Concurrent;

namespace PServiceBus.Cassandra {
    public sealed class Provider<TObject> : IHaveEndpoint, IObjectProvider<TObject> where TObject : class {

        private CassandraCollection<TObject> _collection;
        private static ConcurrentDictionary<string, object> _providers = new ConcurrentDictionary<string, object>();

        public Provider() {
            var isQueue = typeof(IDeleteable).IsAssignableFrom(typeof(TObject));
            DeleteObjectOnRead = isQueue;
            if (isQueue)
                _collection = new CassandraMQ<TObject>();
            else _collection = new CassandraStore<TObject>();
        }

        public Provider(bool isQueue) {
            DeleteObjectOnRead = isQueue;
            if (isQueue)
                _collection = new CassandraMQ<TObject>();
            else _collection = new CassandraStore<TObject>();
        }

        public static Provider<TObject> GetProvider(string endpoint, bool appendTypeNameToEndpoint = false, string endpointAlias = null) {
            return _providers.GetOrAdd(endpoint, key =>
                new Provider<TObject>(isQueue: true)
                {
                    Endpoint = endpoint,
                    IDFunc = x => Guid.NewGuid(),
                    EndpointAlias = endpointAlias,
                    AppendTypeNameToEndpoint = appendTypeNameToEndpoint
                }) as Provider<TObject>;
        }

        public void Clear() {
            _collection.Clear();
        }

        public void Delete() {
            Clear();
        }


        internal void ClearKeyStore() {
            _collection.ClearColumnFamilies(CassandraConstants.KEYVALUES_COLUMN_FAMILY, CassandraConstants.COUNTER_COLUMN_FAMILY);
        }

        private byte[] GetID(TObject obj) {
            return IDFunc(obj).ToByteArray();
        }

        public bool Refresh(TObject obj) {
            return Add(obj);
        }

        public bool Exists(TObject obj) {
            return _collection.Exists(obj);
        }

        public ulong Incr(string key) {
            return _collection.Incr(key);
        }

        public ulong Decr(string key) {
            return _collection.Decr(key);
        }

        public TValue Get<TValue>(string key) {
            return _collection.Get<TValue>(key);
        }

        public void Set<TValue>(string key, TValue value) {
            _collection.Set(key, value);
        }

        public TObject Get(Guid id) {
            return _collection.Get(id);
        }

        public bool Add(TObject obj) {
            return _collection.Add(obj);
        }

        public bool Add(IEnumerable<TObject> list) {
            return _collection.Add(list);
        }

        public bool Delete(IEnumerable<TObject> list) {
            return _collection.Delete(list);
        }

        public bool Exists(Func<TObject, bool> condition) {
            return _collection.Exists(condition);
        }

        public TObject Get(Func<TObject, bool> condition) {
            return _collection.Get(condition);
        }

        public bool Delete(Func<TObject, bool> condition) {
            return _collection.Delete(condition);
        }

        public bool Delete(TObject obj) {
            return _collection.Delete(obj);
        }


        public bool Delete(IEnumerable<Func<TObject, bool>> conditions) {
            return _collection.Delete(conditions);
        }

        private string _endpoint;
        public string Endpoint {
            get { return _endpoint; }
            set { _collection.Endpoint = _endpoint = value; }
        }

        private string _endpointAlias;
        public string EndpointAlias {
            get { return _endpointAlias; }
            set { _collection.EndpointAlias = _endpointAlias = value; }
        }

        private bool _appendTypeNameToEndPoint;
        public bool AppendTypeNameToEndpoint {
            get { return _appendTypeNameToEndPoint; }
            set { _collection.AppendTypeNameToEndpoint = _appendTypeNameToEndPoint = value; }
        }

        public bool DeleteObjectOnRead { get; set; }

        private Func<TObject, Guid> _idFunc;
        public Func<TObject, Guid> IDFunc {
            get { return _idFunc; }
            set { _collection.IDFunc = _idFunc = value; }
        }

        #region IEnumerable<TObject> Members

        public IEnumerator<TObject> GetEnumerator() {
            return _collection.GetEnumerator();
        }

        #endregion

        #region IEnumerable Members

        IEnumerator IEnumerable.GetEnumerator() {
            return GetEnumerator();
        }

        #endregion

        #region IDisposable Members

        public void Dispose() {
            if (_collection != null)
                _collection.Dispose();
        }
        #endregion
    }
}
